{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "initial_id",
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": ""
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 1、获取大模型",
   "id": "a19a02b80c2447d6"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-09-25T20:08:07.158764Z",
     "start_time": "2025-09-25T20:08:03.201838Z"
    }
   },
   "cell_type": "code",
   "source": [
    "#导入 dotenv 库的 load_dotenv 函数，用于加载环境变量文件（.env）中的配置\n",
    "import os\n",
    "\n",
    "import bs4\n",
    "from langchain.agents import create_openai_functions_agent, AgentExecutor\n",
    "from langchain_core.output_parsers import StrOutputParser, JsonOutputParser\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_core.tools import create_retriever_tool\n",
    "from langchain_openai import ChatOpenAI, OpenAIEmbeddings\n",
    "import dotenv\n",
    "from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
    "\n",
    "dotenv.load_dotenv() #加载当前目录下的 .env 文件\n",
    "\n",
    "os.environ['OPENAI_API_KEY'] = os.getenv(\"OPENAI_API_KEY1\")\n",
    "os.environ['OPENAI_BASE_URL'] = os.getenv(\"OPENAI_BASE_URL\")\n",
    "\n",
    "# 创建大模型实例\n",
    "llm = ChatOpenAI(model = \"gpt-4o-mini\")\n",
    "\n",
    "# 直接提供问题，并调用llm\n",
    "response = llm.invoke(\"什么是大模型？\")\n",
    "print( response)"
   ],
   "id": "4eb706d9ce765cba",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "content='大模型（Large Language Model，LLM）是指通过深度学习技术训练的具有丰富参数和能力的人工智能模型，主要用于自然语言处理（NLP）任务。大模型通常具有以下几个特点：\\n\\n1. **参数数量庞大**：大模型通常包含数亿到数百亿个参数，使其能够更好地捕捉语言的复杂性和多样性。\\n\\n2. **训练数据丰富**：大模型通常是在海量的文本数据上进行训练的，这些数据来源于书籍、文章、网页等多种类型的文本，涵盖了广泛的知识领域。\\n\\n3. **多功能性**：大模型能够执行多种语言相关的任务，例如文本生成、翻译、问答、情感分析、文本总结等。\\n\\n4. **上下文理解**：大模型能够理解上下文信息，这使得它在处理复杂的语言结构和语义时表现得更加出色。\\n\\n5. **预训练和微调**：大多数大模型首先进行预训练，然后通过微调（fine-tuning）来优化特定任务的性能。\\n\\n大模型的代表包括OpenAI的GPT系列、Google的BERT、T5等。它们在自然语言理解和生成方面取得了显著的成果，推动了人工智能的发展。' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 285, 'prompt_tokens': 12, 'total_tokens': 297, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_efad92c60b', 'id': 'chatcmpl-CJmY0KGMMPwm1TrRx1bPB7FbN6A5r', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None} id='run--ab1aeffe-282b-4802-8e67-872e4e1d128d-0' usage_metadata={'input_tokens': 12, 'output_tokens': 285, 'total_tokens': 297, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}\n"
     ]
    }
   ],
   "execution_count": 3
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 2、使用提示词模板",
   "id": "52c560424a7ce58f"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-09-25T21:00:17.379067Z",
     "start_time": "2025-09-25T21:00:11.746961Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from langchain_core.prompts.chat import ChatPromptTemplate\n",
    "# 需要注意的一点是，这里需要指明具体的role，在这里是system和用户\n",
    "prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\"system\", \"你是世界级的技术文档编写者\"),\n",
    "        (\"human\", \"{input}\"),\n",
    "    ]\n",
    ")\n",
    "\n",
    "# 我们可以把prompt和具体llm的调用和在一起。\n",
    "chain = prompt | llm\n",
    "message = chain.invoke({\"input\":\"大模型中的LangChain是什么?\"})\n",
    "# message = chain.invoke(\"大模型中的LangChain是什么?\")\n",
    "# message = chain.invoke(input=\"大模型中的LangChain是什么?\")\n",
    "print(message)"
   ],
   "id": "1301abab96328ae2",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "content='LangChain是一个用于构建基于语言模型的应用程序的框架。其主要目标是简化和增强与大型语言模型（如OpenAI的GPT系列或其他 transformer 模型）的交互，使开发者能够更高效地开发和部署应用。这一框架提供了一系列的组件和工具，允许开发者轻松实现复杂的自然语言处理任务。\\n\\n### LangChain的核心功能\\n\\n1. **链式调用**：\\n   LangChain允许将多个语言模型或处理步骤串联在一起，以便根据上下文生成更复杂和更具相关性的响应。\\n\\n2. **环境集成**：\\n   LangChain能够与各种数据源、API及外部工具整合，使得构建富有功能的应用成为可能，包括数据库交互、REST API调用等。\\n\\n3. **自定义链**：\\n   开发者可以创建自定义链，以适应特定的业务需求，同时也可以利用现有的组件。\\n\\n4. **状态管理**：\\n   LangChain提供状态管理功能，使得在多轮对话或复杂交互中，可以保持上下文状态。\\n\\n5. **可扩展性**：\\n   这个框架被设计为友好的并且能够扩展，允许开源贡献者和开发者添加新的功能或优化现有功能。\\n\\n6. **文档和社区支持**：\\n   LangChain有良好的文档和一个活跃的社区，帮助新用户学习并解决技术问题。\\n\\n### 应用场景\\n\\n- **对话系统**：创建智能聊天机器人，能够理解和回应用户的查询。\\n- **内容生成**：自动生成文章、报告或任何文档类型。\\n- **数据汇总**：根据用户输入从多个资料源提取和汇总信息。\\n- **决策支持**：在复杂场景下提供分析与建议。\\n\\n### 总结\\n\\nLangChain是一个强大的工具，通过简化与语言模型的交互，使得开发者能够更容易地创建创新和实用的应用程序。无论是构建基础的对话系统，还是开发复杂的数据处理应用，LangChain都能提供有力的支持。' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 461, 'prompt_tokens': 29, 'total_tokens': 490, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_efad92c60b', 'id': 'chatcmpl-CJnMSYBj3s589aMkOsile04o6z2Vz', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None} id='run--43d20bce-28c8-4ee2-94c9-2195fa1d504d-0' usage_metadata={'input_tokens': 29, 'output_tokens': 461, 'total_tokens': 490, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}\n"
     ]
    }
   ],
   "execution_count": 24
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 3、 使用输出解析器",
   "id": "1bee7203bbab8022"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-09-25T20:22:17.972454Z",
     "start_time": "2025-09-25T20:22:14.657214Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from langchain_core.output_parsers import StrOutputParser,JsonOutputParser\n",
    "\n",
    "# 初始化模型\n",
    "llm = ChatOpenAI(model = \"gpt-4o-mini\")\n",
    "\n",
    "# 创建提示模板\n",
    "prompt = ChatPromptTemplate.from_messages([\n",
    "    (\"system\",\"你是世界级的技术文档编写者\"),\n",
    "    (\"user\",\"{input}\")\n",
    "])\n",
    "\n",
    "# 使用输出解析器\n",
    "# output_parser = StrOutputParser()\n",
    "output_parser = JsonOutputParser()\n",
    "\n",
    "# 将其添加到上一个链中\n",
    "# chain = prompt | llm\n",
    "chain = prompt | llm | output_parser\n",
    "\n",
    "# 调用它并提出同样的问题。答案是一个字符串，而不是ChatMessage\n",
    "# chain.invoke({\"input\":\"LangChain是什么?\"})\n",
    "chain.invoke({\"input\":\"LangChain是什么? 用JSON格式回复，问题用question，回答用answer\"})"
   ],
   "id": "86ce2816d31f86a9",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'question': 'LangChain是什么?',\n",
       " 'answer': 'LangChain是一个用于构建与语言模型（如OpenAI GPT-3）交互的应用程序的框架。它提供了一个高层次的API，以便开发人员能够方便地管理文本生成、链式调用和上下文处理等功能，从而简化在自然语言处理领域的开发工作。LangChain的目标是简化复杂的对话系统、语言理解应用和生成文本的开发过程。'}"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 10
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 4、使用向量存储",
   "id": "1aebb19650489444"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-09-25T20:41:02.724178Z",
     "start_time": "2025-09-25T20:40:56.610369Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from langchain_community.document_loaders import WebBaseLoader\n",
    "import bs4\n",
    "from langchain_openai import OpenAIEmbeddings\n",
    "from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
    "from langchain_community.vectorstores import FAISS\n",
    "\n",
    "loader = WebBaseLoader(\n",
    "    web_path=\"https://www.gov.cn/xinwen/2020-06/01/content_5516649.htm\",\n",
    "    bs_kwargs=dict(parse_only=bs4.SoupStrainer(id=\"UCAP-CONTENT\"))\n",
    ")\n",
    "docs = loader.load()\n",
    "# print(docs)\n",
    "\n",
    "# 对于嵌入模型，这里通过 API调用\n",
    "embedding = OpenAIEmbeddings(model=\"text-embedding-ada-002\")\n",
    "\n",
    "# 使用分割器分割文档\n",
    "text_splitter = RecursiveCharacterTextSplitter(chunk_size=500,chunk_overlap=50)\n",
    "documents = text_splitter.split_documents(docs)\n",
    "print(len(documents))\n",
    "\n",
    "# 向量存储  embeddings 会将 documents 中的每个文本片段转换为向量，并将这些向量存储在 FAISS 向量数据库中\n",
    "vector = FAISS.from_documents(documents,embedding)\n",
    "print(vector)"
   ],
   "id": "da1e74ebd96ec2e5",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "248\n",
      "<langchain_community.vectorstores.faiss.FAISS object at 0x1184b1090>\n"
     ]
    }
   ],
   "execution_count": 19
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 5、RAG(检索增强生成)",
   "id": "e846e174f21950d3"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-09-25T21:01:15.656031Z",
     "start_time": "2025-09-25T21:01:10.001796Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from langchain_core.prompts import PromptTemplate\n",
    "\n",
    "retriever = vector.as_retriever()\n",
    "retriever.search_kwargs = {\"k\":3}\n",
    "docs = retriever.invoke(\"建设用地使用权是什么？\")\n",
    "\n",
    "# for i,doc in enumerate(docs):\n",
    "#     print(f\"⭐第{i+1}条规定：\")\n",
    "#     print(doc)\n",
    "\n",
    "# 6.定义提示词模版\n",
    "prompt_template = \"\"\"\n",
    "你是一个问答机器人。\n",
    "你的任务是根据下述给定的已知信息回答用户问题。\n",
    "确保你的回复完全依据下述已知信息。不要编造答案。\n",
    "如果下述已知信息不足以回答用户的问题，请直接回复\"我无法回答您的问题\"。\n",
    "\n",
    "已知信息:\n",
    "{info}\n",
    "\n",
    "用户问：\n",
    "{question}\n",
    "\n",
    "请用中文回答用户问题。\n",
    "\"\"\"\n",
    "\n",
    "# 7.得到提示词模版对象\n",
    "template = PromptTemplate.from_template(prompt_template)\n",
    "\n",
    "# 8.得到提示词对象\n",
    "prompt = template.format(info=docs,question='建设用地使用权是什么？')\n",
    "\n",
    "## 9. 调用LLM\n",
    "response = llm.invoke(prompt)\n",
    "print(response.content)"
   ],
   "id": "3ef742ac8a79e28a",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "建设用地使用权是指对建设用地的占有和使用权利。根据已有的信息，建设用地使用权可以在土地的地表、地上或者地下设立，且设立时应符合节约资源、保护生态环境和法律、行政法规的要求。建设用地使用权可以通过出让或划拨等方式设立，并可转让、互换、出资、赠与或抵押。其期限届满时，住宅建设用地使用权会自动续期，而非住宅建设用地使用权的续期则依照法律规定处理。\n"
     ]
    }
   ],
   "execution_count": 25
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 6、使用Agent",
   "id": "3c496258a0445d7c"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-09-25T21:22:20.036349Z",
     "start_time": "2025-09-25T21:22:14.746559Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from langchain import hub\n",
    "from langchain_core.tools.retriever import create_retriever_tool\n",
    "from  langchain.agents import create_openai_functions_agent, AgentExecutor\n",
    "# retriever_tool = create_retriever_tool(\n",
    "#     retriever=retriever,\n",
    "#     name=\"CivilCodeRetriever\",\n",
    "#     description=\"搜索有关中华人民共和国民法典的信息。关于中华人民共和国民法典的任何问题，您必须使用此工具!\"\n",
    "# )\n",
    "retriever_tool = create_retriever_tool(\n",
    "    retriever,\n",
    "    \"CivilCodeRetriever\",\n",
    "    \"搜索有关中华人民共和国民法典的信息。关于中华人民共和国民法典的任何问题，您必须使用此工具!\"\n",
    ")\n",
    "tools = [retriever_tool]\n",
    "\n",
    "# https://smith.langchain.com/hub\n",
    "# prompt = hub.pull(owner_repo_commit=\"hwchase17/openai-functions-agent\")\n",
    "prompt = hub.pull(\"hwchase17/openai-functions-agent\")\n",
    "agent = create_openai_functions_agent(llm, tools, prompt)\n",
    "agent_executor = AgentExecutor(agent=agent,tools=tools,verbose=True)\n",
    "\n",
    "# 运行代理\n",
    "agent_executor.invoke({\"input\":\"建设用地使用权是什么\"})"
   ],
   "id": "bca26c4b63bb0237",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001B[1m> Entering new AgentExecutor chain...\u001B[0m\n",
      "\u001B[32;1m\u001B[1;3m\n",
      "Invoking: `CivilCodeRetriever` with `{'query': '建设用地使用权'}`\n",
      "\n",
      "\n",
      "\u001B[0m\u001B[36;1m\u001B[1;3m第三百四十五条　建设用地使用权可以在土地的地表、地上或者地下分别设立。\n",
      "第三百四十六条　设立建设用地使用权，应当符合节约资源、保护生态环境的要求，遵守法律、行政法规关于土地用途的规定，不得损害已经设立的用益物权。\n",
      "第三百四十七条　设立建设用地使用权，可以采取出让或者划拨等方式。\n",
      "工业、商业、旅游、娱乐和商品住宅等经营性用地以及同一土地有两个以上意向用地者的，应当采取招标、拍卖等公开竞价的方式出让。\n",
      "严格限制以划拨方式设立建设用地使用权。\n",
      "第三百四十八条　通过招标、拍卖、协议等出让方式设立建设用地使用权的，当事人应当采用书面形式订立建设用地使用权出让合同。\n",
      "建设用地使用权出让合同一般包括下列条款：\n",
      "（一）当事人的名称和住所；\n",
      "（二）土地界址、面积等；\n",
      "（三）建筑物、构筑物及其附属设施占用的空间；\n",
      "（四）土地用途、规划条件；\n",
      "（五）建设用地使用权期限；\n",
      "（六）出让金等费用及其支付方式；\n",
      "（七）解决争议的方法。\n",
      "第三百四十九条　设立建设用地使用权的，应当向登记机构申请建设用地使用权登记。建设用地使用权自登记时设立。登记机构应当向建设用地使用权人发放权属证书。\n",
      "\n",
      "第三百五十条　建设用地使用权人应当合理利用土地，不得改变土地用途；需要改变土地用途的，应当依法经有关行政主管部门批准。\n",
      "第三百五十一条　建设用地使用权人应当依照法律规定以及合同约定支付出让金等费用。\n",
      "第三百五十二条　建设用地使用权人建造的建筑物、构筑物及其附属设施的所有权属于建设用地使用权人，但是有相反证据证明的除外。\n",
      "第三百五十三条　建设用地使用权人有权将建设用地使用权转让、互换、出资、赠与或者抵押，但是法律另有规定的除外。\n",
      "第三百五十四条　建设用地使用权转让、互换、出资、赠与或者抵押的，当事人应当采用书面形式订立相应的合同。使用期限由当事人约定，但是不得超过建设用地使用权的剩余期限。\n",
      "第三百五十五条　建设用地使用权转让、互换、出资或者赠与的，应当向登记机构申请变更登记。\n",
      "第三百五十六条　建设用地使用权转让、互换、出资或者赠与的，附着于该土地上的建筑物、构筑物及其附属设施一并处分。\n",
      "第三百五十七条　建筑物、构筑物及其附属设施转让、互换、出资或者赠与的，该建筑物、构筑物及其附属设施占用范围内的建设用地使用权一并处分。\n",
      "\n",
      "第三百五十八条　建设用地使用权期限届满前，因公共利益需要提前收回该土地的，应当依据本法第二百四十三条的规定对该土地上的房屋以及其他不动产给予补偿，并退还相应的出让金。\n",
      "第三百五十九条　住宅建设用地使用权期限届满的，自动续期。续期费用的缴纳或者减免，依照法律、行政法规的规定办理。\n",
      "非住宅建设用地使用权期限届满后的续期，依照法律规定办理。该土地上的房屋以及其他不动产的归属，有约定的，按照约定；没有约定或者约定不明确的，依照法律、行政法规的规定办理。\n",
      "第三百六十条　建设用地使用权消灭的，出让人应当及时办理注销登记。登记机构应当收回权属证书。\n",
      "第三百六十一条　集体所有的土地作为建设用地的，应当依照土地管理的法律规定办理。\n",
      "第十三章　宅基地使用权\n",
      "第三百六十二条　宅基地使用权人依法对集体所有的土地享有占有和使用的权利，有权依法利用该土地建造住宅及其附属设施。\n",
      "第三百六十三条　宅基地使用权的取得、行使和转让，适用土地管理的法律和国家有关规定。\n",
      "第三百六十四条　宅基地因自然灾害等原因灭失的，宅基地使用权消灭。对失去宅基地的村民，应当依法重新分配宅基地。\u001B[0m\u001B[32;1m\u001B[1;3m建设用地使用权是法律上对土地使用的一种权利。根据《中华人民共和国民法典》的相关规定，建设用地使用权的主要内容包括以下几个方面：\n",
      "\n",
      "1. **设立和登记**：\n",
      "   - 建设用地使用权可以在土地的地表、地上或地下设立。\n",
      "   - 设立此权利需符合资源节约、生态环境保护的要求，并遵循法律法规关于土地用途的规定。\n",
      "   - 建设用地使用权的设立可以通过出让或划拨等方式，并需要向登记机构申请登记，只有登记后，建设用地使用权才能成立。\n",
      "\n",
      "2. **用途和期限**：\n",
      "   - 建设用地使用权的期限通常由法律或合同规定，住宅建设用地使用权期满后一般会自动续期。\n",
      "   - 使用权人不得随意改变土地用途，若需更改，必须经过相关行政部门的批准。\n",
      "\n",
      "3. **权利和义务**：\n",
      "   - 建设用地使用权人有权将该使用权转让、互换、出资、赠与或抵押，但需遵循相应的法律规定并以书面形式订立合同。\n",
      "   - 使用权人需合理利用土地，并需按规定支付出让金等费用。\n",
      "\n",
      "4. **建筑物所有权**：\n",
      "   - 使用权人所建造的建筑物及其附属设施的所有权属于使用权人，但有反证的除外。\n",
      "\n",
      "5. **其他规定**：\n",
      "   - 如果因公共利益需要提前收回土地，国家需对土地上的建筑物等进行补偿。\n",
      "\n",
      "以上是建设用地使用权的基本框架，具体内容可能会因地区或特定情况而有所不同。\u001B[0m\n",
      "\n",
      "\u001B[1m> Finished chain.\u001B[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'input': '建设用地使用权是什么',\n",
       " 'output': '建设用地使用权是法律上对土地使用的一种权利。根据《中华人民共和国民法典》的相关规定，建设用地使用权的主要内容包括以下几个方面：\\n\\n1. **设立和登记**：\\n   - 建设用地使用权可以在土地的地表、地上或地下设立。\\n   - 设立此权利需符合资源节约、生态环境保护的要求，并遵循法律法规关于土地用途的规定。\\n   - 建设用地使用权的设立可以通过出让或划拨等方式，并需要向登记机构申请登记，只有登记后，建设用地使用权才能成立。\\n\\n2. **用途和期限**：\\n   - 建设用地使用权的期限通常由法律或合同规定，住宅建设用地使用权期满后一般会自动续期。\\n   - 使用权人不得随意改变土地用途，若需更改，必须经过相关行政部门的批准。\\n\\n3. **权利和义务**：\\n   - 建设用地使用权人有权将该使用权转让、互换、出资、赠与或抵押，但需遵循相应的法律规定并以书面形式订立合同。\\n   - 使用权人需合理利用土地，并需按规定支付出让金等费用。\\n\\n4. **建筑物所有权**：\\n   - 使用权人所建造的建筑物及其附属设施的所有权属于使用权人，但有反证的除外。\\n\\n5. **其他规定**：\\n   - 如果因公共利益需要提前收回土地，国家需对土地上的建筑物等进行补偿。\\n\\n以上是建设用地使用权的基本框架，具体内容可能会因地区或特定情况而有所不同。'}"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 31
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
